#include "sdio.h"
#include "../gpio.h"
#include "../PRINT/my_printf.h"
#include "../VIC/vic_reg.h"
#include "../PUBLIC/test.h"

/*
 * GPIOA29/SDCLK0   GPIOA31/SDCMD0   GPIOB1/SDDAT0[0]
 * GPIOB3/SDDAT0[0] GPIOB5/SDDAT0[3] GPIOB7/SDDAT0[3]
 */

void de(uint t){
    while(t--);
}

void sdio0_init(){
    int timeout;

    SDIO sdio0 = (SDIO)BASE_ADDR_SD0;

    IP_RESET_REGISTER1 &= ~(1 << 7);
    IP_RESET_REGISTER1 |= (1 << 7);

    ALIVEPWRGATEREG |= (1 << 0);
    // ALIVEGPIOPADOUTENBSETREG |= (1 << 1);

    __REG(0xC001089C) = 3;
    // __REG(0xC0010800) = 0;;

    printf("ALIVEGPIOPADOUTENBREADREG [%x] %x\r\n", (u32)&ALIVEGPIOPADOUTENBREADREG, ALIVEGPIOPADOUTENBREADREG);

    // GPIOAALTFN1 &= ~((3 << 26) | (3 << 30));
    // GPIOAALTFN1 |= ((1 << 26) | (1 << 30));
    // GPIOBALTFN0 &= ~((3 << 2) | (3 << 6) | (3 << 10) | (3 << 14));
    // GPIOBALTFN0 |= ((1 << 2) | (1 << 6) | (1 << 10) | (1 << 14));

    __REG(0xC001A024) = (__REG(0xC001A024) & 0x33FFFFFF) | 0x44000000;// GPIOA29 31：复用SDCLK SDCMD
    __REG(0xC001B020) = (__REG(0xC001B020) & 0xFFFF3333) | 0x4444;// GPIOB 1 3 5 7：复用SDDAT0[0 - 3]
    __REG(0xC001A040) &= 0x5FFFFFFFu;          // GPIOA 29 31: SLEW: 0-Fast Slew   1-Normal Slew
    __REG(0xC001A044) |= 0xA0000000;           // GPIOA 29 31: SLEW = Use GPIOx_Slew Value
    __REG(0xC001A050) |= 0xA0000000;
    __REG(0xC001A054) |= 0xA0000000;
    __REG(0xC001A048) |= 0xA0000000;
    __REG(0xC001A04C) |= 0xA0000000;
    __REG(0xC001A058) |= 0xA0000000;
    __REG(0xC001A05C) |= 0xA0000000;
    __REG(0xC001A060) |= 0x80000000;
    __REG(0xC001A064) |= 0xA0000000;
    __REG(0xC001B040) &= 0xFFFFFF55;           // Fast Slew
    __REG(0xC001B044) |= 0xAAu;
    __REG(0xC001B050) |= 0xAAu;
    __REG(0xC001B054) |= 0xAAu;
    __REG(0xC001B048) |= 0xAAu;
    __REG(0xC001B04C) |= 0xAAu;
    __REG(0xC001B058) |= 0xAAu;
    __REG(0xC001B05C) |= 0xAAu;
    __REG(0xC001B060) |= 0xAAu;
    __REG(0xC001B064) |= 0xAAu;

    vic_init(43, (u32)sdio0_ISR);

    // SDMMCCLKGEN0L &= ~((0xFF << 5) | (0x7 << 2));
    // SDMMCCLKGEN0L |= (((4 - 1) << 5) | (2 << 2));    // PLL[2] / 4 = 200MHz
    SDMMCCLKGEN0L  = (SDMMCCLKGEN0L & 0xFFFFE003) | 0x28;
    SDMMCCLKENB |= (1 << 2);            // 时钟生成使能

    // printf("SDMMCCLKGEN0L [%x] %x\r\n", (u32)&SDMMCCLKGEN0L, SDMMCCLKGEN0L);
    // printf("SDMMCCLKENB [%x] %x\r\n", (u32)&SDMMCCLKENB, SDMMCCLKENB);

    printf("CTRL [%x] %x\r\n", (u32)&sdio0->CTRL, sdio0->CTRL);
    sdio0->CTRL &= 0xFFFFFF9F;
    sdio0->CTRL = 7;
    while(sdio0->CTRL & 7){
        printf("CTRL [%x] %x\r\n", (u32)&sdio0->CTRL, sdio0->CTRL);
    }
    

    printf("RST_n [%x] %x\r\n", (u32)&sdio0->RST_n, sdio0->RST_n);
    // sdio0->CLKDIV |= 250;         // 分频 250 * 2
    sdio0->RST_n = 1;         // 分频 250 * 2
    printf("RST_n [%x] %x\r\n", (u32)&sdio0->RST_n, sdio0->RST_n);

    printf("CLKDIV_SDIO0 [%x] %x\r\n", (u32)&CLKDIV_SDIO0, CLKDIV_SDIO0);
    // sdio0->CLKDIV |= 250;         // 分频 250 * 2
    CLKDIV_SDIO0 |= 250;         // 分频 250 * 2
    printf("CLKDIV_SDIO0 [%x] %x\r\n", (u32)&CLKDIV_SDIO0, CLKDIV_SDIO0);
    sdio0->CLK_SOURCE = 0;
    
    sdio0->CTYPE = 0;           // 数据位宽，1-bit
    sdio0->BLKSIZ = 512;        // 块大小
    
    sdio0->CTRL |= (1 << 4);    // 中断使能
    sdio0->CLKENA |= (1 << 0);  // 时钟使能

    printf("sdio0->INTMASK [%x] %x\r\n", (u32)&sdio0->INTMASK, sdio0->INTMASK);
    sdio0->INTMASK |= ((1 << 16) | (1 << 2)); // mask使能
    printf("sdio0->INTMASK [%x] %x\r\n", (u32)&sdio0->INTMASK, sdio0->INTMASK);

    printf("POWER_ENABLE %x\r\n", POWER_ENABLE_SDIO0);
    // sdio0->POWER_ENABLE = 1;    // 上电
    POWER_ENABLE_SDIO0 = 1;    // 上电
    printf("POWER_ENABLE %x\r\n", POWER_ENABLE_SDIO0);

    // 发送CMD0
    // for(timeout = 0; timeout < 80; timeout++){
    sdio0->CMDARG = 0;
    // sdio0->CMD = ((1 << 31) | (1 << 29) | (1 << 15));
    sdio0->CMD = ((1 << 29) | (1 << 15));
    printf("cmd0 send [%x] %x\r\n", (u32)&sdio0->CMD, sdio0->CMD);
    sdio0->CMD = (1 << 31);
    printf("cmd0 send %x %x\r\n", sdio0->STATUS, sdio0->CMD);
    // }

    

    timeout = 0x10000;
    while(--timeout){
        if(((sdio0->STATUS > 4) & 0xF) == 1 || ((sdio0->RINTSTS >> 2) & 1) == 1){
            printf("OK %x %x\r\n", sdio0->STATUS, sdio0->RINTSTS);
            break;
        }
    }
    
    if(timeout == 0){
        printf("cmd0 timeout %x %x\r\n", sdio0->STATUS, sdio0->CMD);
    }

    // 发送CMD2
    sdio0->CMDARG = 0;
    sdio0->CMD = ((1 << 31) | (1 << 7) | (1 << 6) | (2 << 0));

    timeout = 0x10000;
    while(--timeout){
        if(((sdio0->STATUS > 4) & 0xF) == 1 || sdio0->RINTSTS){
            printf("OK %x %x\r\n", sdio0->STATUS, sdio0->RINTSTS);
            break;
        }
    }

    if(timeout == 0){
        printf("cmd2 timeout %x %x\r\n", sdio0->STATUS, sdio0->CMD);
    }

    printf("clk_source [%x] %x %x %x %x\r\n", (u32)&sdio0->RESP0, sdio0->RESP0, sdio0->RESP1, sdio0->RESP2, sdio0->RESP3);
}

void sdio0_ISR(){
    printf("sdio0_ISR %x\r\n", 0);
}